package com.itjeffrey.autocode.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.itjeffrey.autocode.bo.LoginInfoBO;
import com.itjeffrey.autocode.bo.RoleInfoTbBO;
import com.itjeffrey.autocode.bo.UserInfoBO;
import com.itjeffrey.autocode.bo.req.IsEnableBO;
import com.itjeffrey.autocode.bo.req.RelateRoleBO;
import com.itjeffrey.autocode.common.ACContext;
import com.itjeffrey.autocode.common.BaseCommon;
import com.itjeffrey.autocode.common.PageResult;
import com.itjeffrey.autocode.common.Result;
import com.itjeffrey.autocode.constant.SysConstant;
import com.itjeffrey.autocode.entity.LoginInfoEntity;
import com.itjeffrey.autocode.entity.ResInfoTbEntity;
import com.itjeffrey.autocode.entity.RoleInfoTbEntity;
import com.itjeffrey.autocode.entity.UserInfoEntity;
import com.itjeffrey.autocode.enums.ExceptionEnum;
import com.itjeffrey.autocode.exception.ACException;
import com.itjeffrey.autocode.mapper.UserInfoMapper;
import com.itjeffrey.autocode.service.LoginService;
import com.itjeffrey.autocode.service.ResInfoTbService;
import com.itjeffrey.autocode.service.RoleInfoTbService;
import com.itjeffrey.autocode.service.UserService;
import com.itjeffrey.autocode.util.BeanOprUtils;
import com.itjeffrey.autocode.util.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @From: Jeffrey
 * @Date: 2020/12/9
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserInfoMapper, UserInfoEntity> implements UserService {

    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private RoleInfoTbService roleInfoTbService;

    @Resource
    private ResInfoTbService resInfoTbService;

    @Resource
    private LoginService loginService;

    /**
     * 上传头像
     *
     * @param multipartFile
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result uploadAvater(MultipartFile multipartFile) {
        //校验由前端执行
        String pathname = System.getProperty(SysConstant.USER_DIR) + SysConstant.AVATER_ABSTRACT_PATH;
        File destFile = new File(pathname);
        if (!destFile.exists()) {
            destFile.mkdirs();
        }
        String filename = multipartFile.getOriginalFilename();
        destFile = new File(pathname, filename);
        try {
            multipartFile.transferTo(destFile);
        } catch (IOException e) {
            e.printStackTrace();
            throw new ACException(ExceptionEnum.AVATER_UPLOAD_FAIL);
        }
        //更新头像
        String loginName = ACContext.getUserContext().getUsername();
        int update = userInfoMapper.updateAvaUrl(filename, loginName);
        if (update != 1) {
            throw new ACException(ExceptionEnum.DATABASE_OPERATE_FAILURE);
        }
        log.info("头像修改成功！");
        return Result.ok(filename);
    }

    /**
     * 获取头像路径
     *
     * @return
     */
    @Override
    public Result getAvaUrl() {
        String avaUrl = userInfoMapper.getAvaUrl(ACContext.getUserContext().getLoginName());
        return Result.ok(avaUrl);
    }

    /**
     * 根据登录名获取用户名称
     *
     * @param loginName
     * @return
     */
    @Override
    @Cacheable(value = "AutoCode::UserInfo", keyGenerator = "keyGenerator", unless = "#result==null")
    public String getUserNameByLoginName(String loginName) {
        if (StringUtils.isBlank(loginName)) {
            return null;
        }
        return userInfoMapper.getUserNameByLoginName(loginName);
    }

    @Override
    public Result queryList(UserInfoBO userInfoBO) {
        PageResult<UserInfoBO> pageResult = new PageResult<UserInfoBO>().setCurPageAndSize(userInfoBO
                .calCurPage());
        LambdaQueryWrapper<UserInfoEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotBlank(userInfoBO.getUsername()), UserInfoEntity::getUsername,
                userInfoBO.getUsername());
        queryWrapper.like(StringUtils.isNotBlank(userInfoBO.getNickname()), UserInfoEntity::getNickname,
                userInfoBO.getNickname());
        queryWrapper.eq(userInfoBO.getAge() != null, UserInfoEntity::getAge,
                userInfoBO.getAge());
        queryWrapper.eq(StringUtils.isNotBlank(userInfoBO.getEmail()), UserInfoEntity::getEmail, userInfoBO.getEmail());
        queryWrapper.eq(StringUtils.isNotBlank(userInfoBO.getPhone()), UserInfoEntity::getPhone, userInfoBO.getPhone());
        queryWrapper.eq(StringUtils.isNotBlank(userInfoBO.getAvaUrl()), UserInfoEntity::getAvaUrl,
                userInfoBO.getAvaUrl());
        queryWrapper.like(StringUtils.isNotBlank(userInfoBO.getAddress()), UserInfoEntity::getAddress,
                userInfoBO.getAddress());
        queryWrapper.apply(StringUtils.isNotBlank(userInfoBO.getLoginName()), "and username in (select user_name " +
                "from login_info_tb where login_name = '" + userInfoBO.getLoginName() + "')");
        Integer count = userInfoMapper.selectCount(queryWrapper);
        queryWrapper.last(SysConstant.DB_KEYWORD_LIMIT + userInfoBO.getCurPage() + SysConstant.SPECIAL_CHAR_3 +
                userInfoBO.getSize());
        List<UserInfoBO> userInfoBOS = userInfoMapper.selectUserList(userInfoBO);
        pageResult.setTotals(count);
        pageResult.setData(userInfoBOS);
        return Result.ok(pageResult);
    }

    @Override
    public Result isEnable(IsEnableBO isEnableBO) {
        userInfoMapper.isEnable(isEnableBO);
        /**
         * 逻辑删除
         * 1.查询登录信息
         * 2.清除登录信息相关的缓存，TokenMap, LoginInfoMap
         */
        if (!isEnableBO.getIsEnabled()) {
            List<LoginInfoEntity> loginInfoEntities = loginService.queryAllLoginInfo(isEnableBO.getUsername());
            for (LoginInfoEntity loginInfoEntity : loginInfoEntities) {
                String loginName = loginInfoEntity.getLoginName();
                BaseCommon.tokenMap.remove(loginName);
                BaseCommon.loginInfoMap.remove(loginName);
            }
        } else {
            //启用，放入loginInfoMap
            LoginInfoEntity loginInfoEntity = loginService.queryOne(isEnableBO.getLoginname());
            BaseCommon.loginInfoMap.put(loginInfoEntity.getLoginName(), BeanOprUtils.copyProperties(loginInfoEntity,
                    LoginInfoBO::new));
        }
        return Result.ok();
    }

    @Override
    public Result queryOne(String loginname) {
        UserInfoBO userInfoBO = userInfoMapper.queryOne(loginname);
        Integer age = userInfoBO.getAge();
        if(age != null){
            Date bithday = DateUtil.ageToDate(age);
            userInfoBO.setBirthday(bithday);
        }
        return Result.ok(userInfoBO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result modUser(UserInfoBO userInfoBO) {
        UserInfoEntity userInfoEntity = new UserInfoEntity();
        BeanUtils.copyProperties(userInfoBO, userInfoEntity);
        userInfoEntity.setAge(DateUtil.dateToAge(userInfoBO.getBirthday()));
        userInfoEntity.setUpdateTime(DateUtil.getCurTime());
        userInfoEntity.setEnabled(true);
        userInfoMapper.updateById(userInfoEntity);
        return Result.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result delete(String loginname) {
        String username = getUserNameByLoginName(loginname);
        //删除用户信息，用户所有登录信息，用户角色表数据, 清除登录信息相关的缓存，TokenMap, LoginInfoMap
        loginService.deleteByUsername(username);
        userInfoMapper.deleteById(username);
        userInfoMapper.deleteUserRole(username);
        return Result.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result relateRole(RelateRoleBO relateRoleBO) {
        LoginInfoEntity loginInfoEntity = loginService.queryOne(relateRoleBO.getLoginName());
        if(loginInfoEntity == null){
            throw new ACException(ExceptionEnum.LOGIN_INFO_NOT_EXISTS);
        }
        relateRoleBO.setUserName(loginInfoEntity.getUserName());
        return Result.ok(userInfoMapper.relateRole(relateRoleBO));
    }

    @Override
    public Result queryRoleInfosByLoginName(String loginName) {
        return roleInfoTbService.queryRoleInfosByLoginName(loginName);
    }

    /**
     * 根据用户名查找所有的资源名
     *
     * @param username
     * @return
     */
    public Set<String> findPermission(String username, String resType) {
        Set<String> resNames = new HashSet<>();
        List<RoleInfoTbBO> roleInfoTbBOS = queryRoleInfosByUsername(username);
        for (RoleInfoTbBO roleInfoTbBO : roleInfoTbBOS) {
            Integer roleId = roleInfoTbBO.getRoleId();
            List<ResInfoTbEntity> resInfoTbEntities = resInfoTbService.queryResInfosByRoleId(roleId, resType);
            if (CollectionUtils.isNotEmpty(resInfoTbEntities)) {
                if (SysConstant.RES_TYPE_CD.equals(resType)) {
                    resNames =
                            resInfoTbEntities.stream().map(ResInfoTbEntity::getResName).collect(Collectors.toSet());

                } else if (SysConstant.RES_TYPE_JK.equals(resType)) {
                    resNames = resInfoTbEntities.stream().map(ResInfoTbEntity::getResUrl).collect(Collectors.toSet());
                }
            }
        }
        return resNames;
    }


    /**
     * 根据用户名查询角色列表
     *
     * @param username
     * @return
     */
    public List<RoleInfoTbBO> queryRoleInfosByUsername(String username) {
        if (StringUtils.isBlank(username)) {
            return null;
        }
        List<RoleInfoTbEntity> roleInfoTbBOS = roleInfoTbService.queryRoleInfosByUsername(username);
        List<RoleInfoTbBO> collect = roleInfoTbBOS.stream().map(t -> {
            RoleInfoTbBO roleInfoTbBO = new RoleInfoTbBO();
            BeanUtils.copyProperties(t, roleInfoTbBO);
            return roleInfoTbBO;
        }).collect(Collectors.toList());
        return collect;
    }

    /**
     * 用户是否有某个资源的权限
     *
     * @param username,resName
     * @return
     */
    public boolean hasResource(String username, String resName, String resType) {
        Set<String> resNames = this.findPermission(username, resType);
        if (CollectionUtils.isNotEmpty(resNames) && resNames.contains(resName)) {
            return true;
        }
        return false;
    }

}
